package com.googlecode.tracey.audit;

import com.googlecode.totallylazy.Callable1;
import com.googlecode.tracey.headers.Headers;
import com.googlecode.tracey.id.TraceyIdValue;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;

import static com.googlecode.totallylazy.Sequences.sequence;
import static java.lang.String.format;

public class MessageFormatter {
    private final static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss,SSS";
    private final Clock clock;
    private final IdGenerator idGenerator;
    private final DateFormat dateFormat;

    public MessageFormatter(Clock clock, IdGenerator idGenerator, DateFormat dateFormat) {
        this.clock = clock;
        this.idGenerator = idGenerator;
        this.dateFormat = dateFormat;

    }

    public MessageFormatter(Clock clock, IdGenerator idGenerator) {
        this(clock, idGenerator, getDefaultDateFormat());
    }

    public String formatMessage(TraceyIdValue traceyId, TraceyAuditMessage traceyAuditMessage) {
        LinkedHashMap<String, String> ordersHeaders = new LinkedHashMap<String, String>();

        ordersHeaders.put(Headers.MESSAGE_ID, idGenerator.generateId());
        ordersHeaders.put(Headers.FROM, traceyAuditMessage.from());
        ordersHeaders.put(Headers.TO, traceyAuditMessage.to());
        ordersHeaders.putAll(traceyAuditMessage.headers());
        final String headersAsLine = convertToLine(ordersHeaders);
        Date logDate = traceyAuditMessage.logDate() == null ? clock.now() : traceyAuditMessage.logDate();
        return format("%s Begin: %s\n%s\n\n%s\nEnd: %s\n", dateFormat.format(logDate), traceyId, headersAsLine, traceyAuditMessage.payload(), traceyId);
    }

    private String convertToLine(LinkedHashMap<String, String> ordersHeaders) {
        return sequence(ordersHeaders.entrySet()).map(toHeader()).toString("\n");
    }

    private Callable1<Map.Entry<String, String>, String> toHeader() {
        return new Callable1<Map.Entry<String, String>, String>() {
            public String call(Map.Entry<String, String> entry) throws Exception {
                return String.format("%s: %s", entry.getKey(), entry.getValue());
            }
        };
    }

    public static DateFormat getDefaultDateFormat() {
        return new SimpleDateFormat(DEFAULT_DATE_FORMAT);
    }
}
